/*****************************************************************************
 * IV_Spec.c
 *
 * This file contains functions for doing IV Spectroscopy.
 *
 *
 *
 *****************************************************************************/

 
#include <cdef21369.h>
#include <stdio.h>
#include <def21369.h>
#include <21369.h>
#include <math.h>
#include <signal.h>

const unsigned int MAXPTS = 600;		// Max size of the allocated array

// IV defalt parameters
float npts = 200;
float startV = -5.0;
float endV = 5.0;
float IVtime = 0.01; 		// Time in seconds
float coreclk = 331.776e6;	// core clock speed
float IVData[500] = {0.0};
float IVper = 0.00005;		// IV period in seconds
float IVvlts;
float Vstep = 0.05;			// Voltage step size
int TIV = 16589;			// IV Period in core clock waits
int count = 0;				// a counter for the IV loop
int maxcnt = 400;			// maximum counts = 2*npts
float resetV = 2.0;
int resetZ = 0;
int nreads = 1;
float readT = 5e-6;

extern const int Z_CH_H;	// The high gain z channel
extern const int Z_CH_L;	// The high gain z channel
extern const int TIP_CH;	// Tip channel
extern int Tpid;			// Servo PID period

// Useful externally defined functions
extern void SwitchChannel(int);
extern void SetCurrentV(int);
extern void timer_isr(int);
extern float ReceiveFloat(void);
extern void SendFlt(float);
extern void delay(int);
extern void StartServo(void);
extern void StopServo(void);

extern long ReadSPI(void);
extern void WriteSPI(unsigned long);
extern float ADCtoVolts(long);
extern unsigned long VoltstoDAC(float);

// Prototypes
void IVSetup(void);
void DoIV(float,int);
void EndIV(void);
void timer_IV(int);
void ResumeTunneling();

/*** Begin IV Code ***/

void IVSetup()
{
	// Get the IV parameters off of the Serial line
	npts = ReceiveFloat();
	startV = ReceiveFloat();
	endV = ReceiveFloat();
	IVtime = ReceiveFloat();
	
	if(npts > MAXPTS) npts = MAXPTS;
	IVper = IVtime * powf(npts,-1);
	TIV = (int)(coreclk * IVper); // calculate the ISR wait time
	Vstep = (endV-startV)*powf(npts,-1); // calculated the voltage increment
	nreads = (int)(0.5 * IVper * powf(readT,-1)); //calculate the max reads with factor of 2 safety
	if(nreads < 1) nreads = 1;
}

void DoIV(float vTip,int zCH)
{
	resetZ = zCH;
	resetV = vTip;
	StopServo();
	interrupts (SIG_TMZ0, timer_IV); /* enable high priority timer interrupt */
   	timer_set(TIV,TIV);              /* set tperiod and tcount of the timer */
   	SwitchChannel(TIP_CH);			// Switch to the tip bias channel for output
   	WriteSPI(VoltstoDAC(startV)); 	// write start value to DAC
   	IVvlts = startV;
   	delay(TIV);						// settle the tip
   	count = 0; 						// reset the counter
	maxcnt = 2*npts; 				//set the max count
   	StartServo();
}

void timer_IV(int sig)
{
	float curr = 0;
	int i = 0;
	for(i=0;i<nreads;i++)
	{
		curr += ADCtoVolts(ReadSPI());
	}
	curr = curr * powf((float)nreads,-1);
	IVData[count] = curr; // store the data
	
	/* Increment the step or end the IV procedure */
	if(count < npts) IVvlts = IVvlts + Vstep;
	else if(npts < count < maxcnt) IVvlts = IVvlts - Vstep;
	WriteSPI(VoltstoDAC(IVvlts)); // write the next voltage value
	
	if (count >= maxcnt) EndIV();
	count = count + 1; // increment the counter
}

void EndIV()
{
	StopServo();							//stop the IV loop
   	
	if(count == maxcnt) *pUART0THR = 0x44; 	//add 1 char of data to the buffer
	else *pUART0THR = 0x46; 					//add 1 char of data to the buffer
    while(!(*pUART0LSR & UARTTHRE)); 		//wait until it is sent
}

void ResumeTunneling()
{   
	SwitchChannel(TIP_CH);
    WriteSPI(VoltstoDAC(resetV));		 	// write tip bias to DAC
   	delay(TIV);								// settle the tip
	
	interrupts (SIG_TMZ0, timer_isr);		/* enable high priority timer interrupt */
   	timer_set(Tpid,Tpid);					/* set tperiod and tcount of the timer */
   	SwitchChannel(resetZ);			// Switch to the correct z servo channel
   	StartServo();
}

void SendIV()
{
	int i = 0;
	for(i=0;i<maxcnt;i++)
	{
		SendFlt(IVData[i]);
	}
}
